package com.sztx.pay.center.rpc.component;

import java.util.Date;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.mortbay.log.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.sztx.pay.center.common.util.Constance;
import com.sztx.pay.center.common.util.Constance.BindCardType;
import com.sztx.pay.center.common.util.Constance.CallBackOrderState;
import com.sztx.pay.center.common.util.Constance.CardActType;
import com.sztx.pay.center.common.util.Constance.DistributeType;
import com.sztx.pay.center.common.util.Constance.PayFlowState;
import com.sztx.pay.center.common.util.Constance.PayFlowType;
import com.sztx.pay.center.common.util.Constance.TradeMessageType;
import com.sztx.pay.center.common.util.Constance.TradeOrderType;
import com.sztx.pay.center.common.util.Constance.UserActType;
import com.sztx.pay.center.common.util.Constance.WithDrawType;
import com.sztx.pay.center.common.util.Constance.WithdrawState;
import com.sztx.pay.center.common.util.DateUtil;
import com.sztx.pay.center.common.util.JFUtils;
import com.sztx.pay.center.common.util.ValidateUtil;
import com.sztx.pay.center.common.yhbf.YHBFSensitiveEnc;
import com.sztx.pay.center.core.service.AccountService;
import com.sztx.pay.center.core.service.ActService;
import com.sztx.pay.center.core.service.BillnoService;
import com.sztx.pay.center.core.service.CallBackService;
import com.sztx.pay.center.core.service.MqMessageService;
import com.sztx.pay.center.core.service.OrderMappingService;
import com.sztx.pay.center.core.service.PayCoreCallBack;
import com.sztx.pay.center.core.service.PayCoreService;
import com.sztx.pay.center.core.service.SettleService;
import com.sztx.pay.center.core.service.UserInfoService;
import com.sztx.pay.center.core.service.bean.CallBackInfo;
import com.sztx.pay.center.core.service.bean.PayCoreDistribute;
import com.sztx.pay.center.core.service.bean.PayCoreResult;
import com.sztx.pay.center.core.service.bean.PayCoreTradeInfo;
import com.sztx.pay.center.core.service.bean.PayCoreTransferReq;
import com.sztx.pay.center.core.service.util.SettleTradeType;
import com.sztx.pay.center.core.service.util.SettleType;
import com.sztx.pay.center.dataaccess.dao.mysql.GatewaySwiftCodeBankIdMappingMysqlDAO;
import com.sztx.pay.center.dataaccess.dao.mysql.OrderWithdrawMysqlDAO;
import com.sztx.pay.center.dataaccess.dao.redis.LockRedisDAO;
import com.sztx.pay.center.dataaccess.domain.OrderWithdrawDO;
import com.sztx.pay.center.dataaccess.domain.UserActDO;
import com.sztx.pay.center.dataaccess.domain.UserBindCardDO;
import com.sztx.pay.center.dataaccess.domain.UserInfoDO;
import com.sztx.pay.center.rpc.api.domain.TradeBaseRequest;
import com.sztx.pay.center.rpc.api.domain.TradeFlowMessage;
import com.sztx.pay.center.rpc.api.domain.TradeResponse;
import com.sztx.pay.center.rpc.api.domain.WithdrawRequest;
import com.sztx.pay.risk.rpc.api.domain.TradeType;
import com.sztx.se.common.exception.BusinessException;
import com.sztx.se.common.util.StringUtil;
/**
 * 提现

withdrawType == 1   余额提现
   	余额账户/缴费商账户代发
withdrawType == 2   返利金提现
  	返利金账户代发
 * @author LEIQ
 *
 */
public class TradeWithdrawService extends TradeService implements PayCoreCallBack{
	OrderWithdrawMysqlDAO orderWithdrawMysqlDAO;
	
	AccountService accountService;
	
	BillnoService billnoService;
	
	PayCoreService payCoreService;
	
	SettleService settleService;
	
	@Autowired
	CallBackService callBackService;
	
	@Autowired
	OrderMappingService orderMappingService;
	@Autowired
	private LockRedisDAO lockRedisDAO;
	@Autowired
	private ActService actService;
	@Autowired
	private UserInfoService userInfoService;
	@Autowired
	private GatewaySwiftCodeBankIdMappingMysqlDAO gatewaySwiftCodeBankIdMappingMysqlDAO;
	@Autowired
	private MqMessageService mqMessageService;
	
//	private long calculateHandlingFee;//手续费
//	private long payAmount;//实际提现金额
	
	@Override
	void checkPrivateParam(Map<String, String> params) {
		String userId = params.get("payerUserId");
		String withdrawType = params.get("withdrawType");
		String payeeUserId = params.get("payeeUserId");
		String bindNo = params.get("bindNo");
		String amount = params.get("amount");
		String withdrawTime = params.get("withdrawTime");
		
		String channelId = params.get("channelId");
		String businessType = params.get("businessType");
		String notifyUrl = params.get("notifyUrl");
		
		
		ValidateUtil.isNotBlank(channelId, "channelId不能为空");
		ValidateUtil.isNotBlank(businessType, "businessType不能为空");
		ValidateUtil.isNotBlank(userId, "userId不能为空");
		ValidateUtil.isNotBlank(withdrawType, "withdrawType不能为空");
		if(withdrawType.equals("2")){
			ValidateUtil.isNotBlank(payeeUserId, "payeeUserId不能为空");
		}
		ValidateUtil.isNotBlank(amount, "amount不能为空");
		if (StringUtil.isNotBlank(bindNo)) {
			ValidateUtil.strEqualLen(bindNo, 8, "bindNo格式不正确");
		}
		if (withdrawTime != null) {
			ValidateUtil.isDate(withdrawTime, "yyyyMMddHHmmss", "withdrawTime格式不正确");
		}
		ValidateUtil.isNotBlank(notifyUrl, "notifyUrl不能为空");
		
	}

	@Override
	boolean isRepeatOrder(Map<String, String> params) {
		
		String orderId = params.get("orderId");
		
		//先从redis判断是否存在订单号
		boolean flag = lockRedisDAO.lockOrder(orderId, "", "checkRepeat");
		if(!flag){
			return false;
		}
		
		OrderWithdrawDO orderWithdrawDO = orderWithdrawMysqlDAO.findByOrderId(orderId);
		if (orderWithdrawDO != null) {
			return true;
		}
		
		return false;
	}

	@Override
	String recordOrder(TradeBaseRequest request) {
		if (!(request instanceof WithdrawRequest)) {
			logger.error("请求参数错误request不是WithdrawRequest对象");
			throw new BusinessException("服务器正忙，请稍后再试");
		}		
		WithdrawRequest withdrawRequest = (WithdrawRequest) request;
		
		int amount = withdrawRequest.getAmount();
		String attach = withdrawRequest.getAttach();
		String notifyUrl = withdrawRequest.getNotifyUrl();
		String orderId = withdrawRequest.getOrderId();
		String payeeUserId = withdrawRequest.getPayeeUserId();
		String srcIp = withdrawRequest.getSrcIp();
		String returnUrl = withdrawRequest.getReturnUrl();
		String srcChannel = withdrawRequest.getSrcChannel();
		int withdrawType = withdrawRequest.getWithdrawType();
		String payerUserId = withdrawRequest.getPayerUserId();
		String bindNo = withdrawRequest.getBindNo();
		String withdrawTime = withdrawRequest.getWithdrawTime();
		String platChannelId = withdrawRequest.getChannelId();
		String businessType = withdrawRequest.getBusinessType();
		
		
		SettleTradeType settleTradeType = null;
		if(payerBindCardInfo != null){
			Integer	bindType = payerBindCardInfo.getBindType(); 
			if(withdrawType == WithDrawType.WITHDRAW_BERBON.getCode() && bindType == 2){
				settleTradeType = SettleTradeType.WITHDRAW_BERBON_BANKCARD;
			}else if(withdrawType == WithDrawType.WITHDRAW_BERBON.getCode() && bindType == 3){
				settleTradeType = SettleTradeType.WITHDRAW_BERBON_ALIPAY;
			}else if(withdrawType == WithDrawType.WITHDRAW_REBATE.getCode() && bindType == 2){
				settleTradeType = SettleTradeType.WITHDRAW_PROFIT_BANKCARD;
			}else if(withdrawType == WithDrawType.WITHDRAW_REBATE.getCode() && bindType == 3){
				settleTradeType = SettleTradeType.WITHDRAW_PROFIT_ALIPAY;
			}else if(withdrawType == WithDrawType.WITHDRAW_SCAN_REBATE.getCode() && bindType == 2){
				settleTradeType = SettleTradeType.WITHDRAW_SCAN_PROFIT_BANKCARD;
			}else if(withdrawType == WithDrawType.WITHDRAW_SCAN_REBATE.getCode() && bindType == 3){
				settleTradeType = SettleTradeType.WITHDRAW_SCAN_PROFIT_ALIPAY;
			}else{
				throw new BusinessException("该卡不能进行提现");
			}
		}else {
			settleTradeType = SettleTradeType.TRANSFER_PROFIT_BERBON;
		}
		
	
		
		//生成提现订单号
		String withdrawOrderId = billnoService.nextWithdrawNo();
		//查询手续费
		
		long calculateHandlingFee = settleService.calculateHandlingFee(settleTradeType, SettleType.NOW, payerUserId, amount,platChannelId,null,null);
		
		if(amount <= calculateHandlingFee){
			throw new BusinessException("手续费不能大于、等于交易金额");
		}
		long payAmount = (long) amount - calculateHandlingFee;
		//this.payAmount = payAmount;
		//查询提现卡信息
//		if(payerBindCardInfo == null){
//			logger.error("当前用户未绑定银行卡,payerBindCardInfo为null");
//			throw new BusinessException("当前用户未绑定银行卡");
//		}
		String bankId = null;
		String channelId = null;
		if(payerBindCardInfo != null){
			bankId = payerBindCardInfo.getBankId();
			channelId = payerBindCardInfo.getChannelId();
		}
		
		OrderWithdrawDO orderWithdrawDO = new OrderWithdrawDO();
		orderWithdrawDO.setWithdrawOrderId(withdrawOrderId);
		orderWithdrawDO.setPayerUserId(payerUserId);
		orderWithdrawDO.setPayerUserAct(payerActInfo.getActNo());
		orderWithdrawDO.setRemark(attach);
		orderWithdrawDO.setPayBankId(bankId);
		orderWithdrawDO.setWithdrawAmount((long) amount);
		orderWithdrawDO.setPayAmount(payAmount);
		orderWithdrawDO.setWithdrawFee(calculateHandlingFee);
		orderWithdrawDO.setWithdrawType((byte) withdrawType);
		orderWithdrawDO.setOrderStatus((byte)WithdrawState.WITHDRAW_STATUS_INIT.getCode());
		orderWithdrawDO.setOrderDesc(WithdrawState.WITHDRAW_STATUS_INIT.getDesc());
		
		orderWithdrawDO.setReferUserId(payeeUserId);
		orderWithdrawDO.setPayChannelId(channelId);
		orderWithdrawDO.setWithdrawChannel((byte) Integer.parseInt(srcChannel));
		
		orderWithdrawDO.setInnerStatus(1);
		orderWithdrawDO.setNotifyUrl(notifyUrl);
		orderWithdrawDO.setOrderId(orderId);
		orderWithdrawDO.setAddTime(new Date());
		orderWithdrawDO.setReturnUrl(returnUrl);
		orderWithdrawDO.setSourceIp(srcIp);
		orderWithdrawDO.setVerifyType(new Byte("0"));
		

		orderWithdrawDO.setPayTime(null);
		orderWithdrawDO.setPayerBindNo(bindNo);
		if(withdrawTime != null){
			orderWithdrawDO.setWithdrawTime(withdrawTime);
		}
		orderWithdrawDO.setPlatChannelId(platChannelId);
		orderWithdrawDO.setBusinessType(businessType);
		orderWithdrawMysqlDAO.save(orderWithdrawDO);
		
		return withdrawOrderId;
	}



	@Override
	UserBindCardDO getPayerBindInfo(Map<String, String> params) {
		String bindNo = params.get("bindNo");
		String payerUserId = params.get("payerUserId");
		UserBindCardDO userBindCardDO = accountService.findUserBindInfo(bindNo, payerUserId, null);
		if(userBindCardDO == null){
			throw new BusinessException("未查询到绑定号【"+bindNo+"】相关信息");
		}
		return userBindCardDO;
	}
	
	@Override
	UserBindCardDO getPayeeBindInfo(Map<String, String> params) {
		
		return null;
	}

	public AccountService getAccountService() {
		return accountService;
	}

	public void setAccountService(AccountService accountService) {
		this.accountService = accountService;
	}

	public BillnoService getBillnoService() {
		return billnoService;
	}

	public void setBillnoService(BillnoService billnoService) {
		this.billnoService = billnoService;
	}

	public PayCoreService getPayCoreService() {
		return payCoreService;
	}

	public void setPayCoreService(PayCoreService payCoreService) {
		this.payCoreService = payCoreService;
	}

	public SettleService getSettleService() {
		return settleService;
	}

	public void setSettleService(SettleService settleService) {
		this.settleService = settleService;
	}

	@Override
	UserActDO getPayerActInfo(TradeBaseRequest request) {
		if (!(request instanceof WithdrawRequest)) {
			logger.error("请求参数错误request不是WithdrawRequest对象");
			throw new BusinessException("服务器正忙，请稍后再试");
		}
		WithdrawRequest withdrawRequest = (WithdrawRequest) request;
		
		String payerUserId = withdrawRequest.getPayerUserId();	
		String channelId = withdrawRequest.getChannelId();
		return getPayerActInfo(payerUserId, channelId);
	}
	
	private UserActDO getPayerActInfo(String payerUserId,String channelId) {
		UserActDO userActDO = null;
		UserInfoDO userInfoDO = userInfoService.findUserInfo(payerUserId);
		if(userInfoDO == null){
			throw new BusinessException("帐号【"+payerUserId+"】不存在");
		}
		Integer userType = userInfoDO.getUserType();
		boolean isJfChannel = JFUtils.isJFChannel(channelId);
		boolean isJfUser = (userType.intValue() & Constance.UserType.AGENT.getCode()) != 0;
		if(isJfChannel){
			//throw new BusinessException("该帐号【"+payerUserId+"】暂不支持此交易");
			//是缴费商用户
			if(!isJfUser){
				throw new BusinessException("该帐号【"+payerUserId+"】暂不支持此交易");
			}
			userActDO = actService.findValidActInfo(payerUserId, UserActType.JF,true);
		}else{
			//其他类型用户
			//userActDO = actService.findUserAct(payerUserId, UserActType.CASH);
			userActDO = actService.findValidActInfo(payerUserId, UserActType.CASH, true);
		}
		if (userActDO == null) {
			throw new BusinessException(payerUserId+"账户不存在");
		}
		userActDO.setUserType(userType);
		return userActDO;
	}

	@Override
	UserActDO getPayeeActInfo(TradeBaseRequest request) {
//		if (!(request instanceof WithdrawRequest)) {
//			logger.error("请求参数错误request不是WithdrawRequest对象");
//			throw new BusinessException("服务器正忙，请稍后再试");
//		}		
//		WithdrawRequest withdrawRequest = (WithdrawRequest) request;
//		String payeeUserId = withdrawRequest.getPayeeUserId();
//	
//		return accountService.findRealActInfo(payeeUserId, 1);//余额账户
		return null;
	}

	public OrderWithdrawMysqlDAO getOrderWithdrawMysqlDAO() {
		return orderWithdrawMysqlDAO;
	}

	public void setOrderWithdrawMysqlDAO(OrderWithdrawMysqlDAO orderWithdrawMysqlDAO) {
		this.orderWithdrawMysqlDAO = orderWithdrawMysqlDAO;
	}

	
	
	//判断余额
	private void checkAmountValid(OrderWithdrawDO orderWithdrawDO){
		WithDrawType withdrawType = WithDrawType.valueOf(orderWithdrawDO.getWithdrawType());
		//判断余额是否足够
		if(withdrawType == WithDrawType.WITHDRAW_BERBON){
			String channelId = orderWithdrawDO.getPlatChannelId();
			boolean isJfChannel = JFUtils.isJFChannel(channelId );
			long balance = 0;
			if(isJfChannel){
				balance = accountService.queryBalance(orderWithdrawDO.getPayerUserId(), UserActType.JF.getCode(),true); 
			}else{
				balance = accountService.queryBalance(orderWithdrawDO.getPayerUserId(), UserActType.CASH.getCode(),true);
			}
			
			if(withdrawType == WithDrawType.WITHDRAW_BERBON &&balance < orderWithdrawDO.getPayAmount()){
				updateWithDrawOrderState(orderWithdrawDO.getWithdrawOrderId(), WithdrawState.WITHDRAW_STATUS_FAIL);
				throw new BusinessException("余额不足");
			}
		}
	}
	//扣除手续费
//	private void tansferPayFee(OrderWithdrawDO orderWithdrawDO){
//		WithDrawType withdrawType = WithDrawType.valueOf(orderWithdrawDO.getWithdrawType());
//		TradeOrderType tradeOrderType = withdrawType == 
//				WithDrawType.WITHDRAW_BERBON ? TradeOrderType.BALANCE_WITHDRAW_ORDER : TradeOrderType.PROFIT_WITHDRAW_ORDER;
//		
//		String mappingOrderId = orderMappingService.getMappingOrderId(orderWithdrawDO.getWithdrawOrderId(), (byte)tradeOrderType.getCode());
//		PayCoreTransferReq req = new PayCoreTransferReq();
//		req.setAmount(orderWithdrawDO.getWithdrawFee());
//		req.setAttach(orderWithdrawDO.getRemark());
//		req.setOrderId(mappingOrderId);
//		req.setOriginOrderId(orderWithdrawDO.getWithdrawOrderId());
//		req.setPayeeActNo(null);
//		req.setPayeeUserType(1);
//		req.setPayeeActType(UserActType.TRADE);
//		req.setPayeeUserId(Constance.USER_ID_SZTX);
//		
//		req.setPayerActNo(null);
//		req.setPayerUserType(payerActInfo.getUserType());
//		req.setPayerActType(UserActType.valueOf(payerActInfo.getActType()));
//		req.setPayerUserId(payerActInfo.getUserId());
//		
//		req.setTradeOrderType(tradeOrderType);
//		payCoreService.balanceTransfer(req );
//		
//	}
	
	
	@Override
	@Transactional
	TradeResponse invokePayCore(Map<String, String> params) {
		String tradeOrderId = params.get("tradeOrderId");
		OrderWithdrawDO orderWithdrawDO = orderWithdrawMysqlDAO.findById(tradeOrderId);
		WithDrawType withdrawType = WithDrawType.valueOf(orderWithdrawDO.getWithdrawType());
		String bindNo = orderWithdrawDO.getPayerBindNo();
		
		
		if(StringUtil.isNotBlank(bindNo)){
			//检查资金余额
			checkAmountValid(orderWithdrawDO);
		}
	
		//是否立即提现
		boolean withDrawNowFlag = withDrawNow(orderWithdrawDO);		
		TradeResponse resonse = new TradeResponse();
		PayCoreResult result = null;
		if(withDrawNowFlag){
			logger.info("-------------------send mq to tradeFlow start---------------------");
			sendTradeFlowMessage(orderWithdrawDO, 1, "扣款成功");
			updateWithDrawOrderState(tradeOrderId, WithdrawState.WITHDRAW_STATUS_IN);
			if(withdrawType == WithDrawType.WITHDRAW_REBATE || withdrawType == WithDrawType.WITHDRAW_SCAN_REBATE){
				b2cTansfer(orderWithdrawDO,withdrawType);
				//返利金提现到余额
				if(StringUtil.isBlank(bindNo)){
					updateWithDrawOrderState(orderWithdrawDO.getWithdrawOrderId(), WithdrawState.WITHDRAW_STATUS_SUCCESS);
					callBack(orderWithdrawDO.getWithdrawOrderId(), Constance.WithdrawState.WITHDRAW_STATUS_SUCCESS,"提现成功");
					resonse.setTradeOrderId(tradeOrderId);
					resonse.setResultCode(String.valueOf(PayFlowState.SUCCESS.getCode()));
					resonse.setResultMsg("提现成功");
					sendTradeFlowMessage(orderWithdrawDO, 2, "佣金转入余额成功");
					return resonse;
				}
			}
			result = innerWithDraw(orderWithdrawDO);
			//更新订单状态
			resolveResult(result);
			PayFlowState payFlowState = PayFlowState.valueOf(result.getTradeSataus());
			if(payFlowState.equals(PayFlowState.FAIL) && (withdrawType == WithDrawType.WITHDRAW_REBATE || withdrawType == WithDrawType.WITHDRAW_SCAN_REBATE)){
				//需要进行退款
				c2bRefundTansfer(orderWithdrawDO,withdrawType);
			}
			
		}
		
		resonse.setTradeOrderId(tradeOrderId);
		
		resonse.setResultCode(String.valueOf(PayFlowState.PAYING.getCode()));
		resonse.setResultMsg("提现中");
		if(result != null){
			PayFlowState payFlowState = PayFlowState.valueOf(result.getTradeSataus());
			if(payFlowState.equals(PayFlowState.FAIL)){
				resonse.setResultCode(String.valueOf(PayFlowState.FAIL.getCode()));
				if(StringUtils.isNoneBlank(result.getTradeDesc())){
					resonse.setResultMsg(result.getTradeDesc());
				}else{
					resonse.setResultMsg(PayFlowState.FAIL.getDesc());
				}
				
			}
		}
		return resonse;
	}
	private boolean resolveResult(PayCoreResult result){
		PayFlowState payFlowState = PayFlowState.valueOf(result.getTradeSataus());
		String mappingOrderId = result.getReferOrderId();
		
		String referOrderId = null;
		if(payFlowState != PayFlowState.SUCCESS){
			//映射表反查订单
			referOrderId = orderMappingService.getTradeOrderId(mappingOrderId);
		}
		if(payFlowState == PayFlowState.SUCCESS ){
			return true;
		}else if(payFlowState == PayFlowState.FAIL){
			updateWithDrawOrderState(referOrderId, WithdrawState.WITHDRAW_STATUS_FAIL);
			callBack(referOrderId, Constance.WithdrawState.WITHDRAW_STATUS_FAIL,result.getTradeDesc());
		}else if(payFlowState == PayFlowState.EXCEPTION){
			updateWithDrawOrderState(referOrderId, WithdrawState.WITHDRAW_STATUS_EXCEPTION);
			callBack(referOrderId, Constance.WithdrawState.WITHDRAW_STATUS_EXCEPTION,result.getTradeDesc());
		}else if(payFlowState == null){
			updateWithDrawOrderState(referOrderId, WithdrawState.WITHDRAW_STATUS_EXCEPTION);
			callBack(referOrderId, Constance.WithdrawState.WITHDRAW_STATUS_EXCEPTION,result.getTradeDesc());
		}
		return false;
	}
	@Override
	void handerPayCoreResult() {
		
		
	}

	
	
	private void updateWithDrawOrderState(String withdrawOrderId,WithdrawState state){
		OrderWithdrawDO orderWithdrawDO = new OrderWithdrawDO();
		orderWithdrawDO.setWithdrawOrderId(withdrawOrderId);
		orderWithdrawDO.setOrderStatus((byte) state.getCode());
		orderWithdrawDO.setOrderDesc(state.getDesc());
		orderWithdrawMysqlDAO.update(orderWithdrawDO);	
	}

	@Override
	public void callPayResult(PayCoreTradeInfo tradeInfo) {
		Log.info("==========================withdraw=======================回调 tradeInfo:"+JSONObject.toJSONString(tradeInfo));
		
		String mappingOrderId = tradeInfo.getReferOrderId();
		//映射表反查订单
		String referOrderId = orderMappingService.getTradeOrderId(mappingOrderId);
		
		String payCoreOrderId = tradeInfo.getPayCoreOrderId();
		PayFlowState payFlowState = tradeInfo.getPayFlowState();
		TradeOrderType tradeOrderType = tradeInfo.getTradeOrderType();  
		PayFlowType payFlowType = tradeInfo.getPayFlowType();
	    String payeeUserId = tradeInfo.getPayeeUserId();
	    int payeeUserType = tradeInfo.getPayeeUserType(); 
	    String payerUserId = tradeInfo.getPayerUserId();
	    int payerUserType = tradeInfo.getPayerUserType();
		long amount = tradeInfo.getAmount();
		String payFlowDesc = tradeInfo.getPayFlowDesc();
		
		WithdrawState withdrawState = null;
		if(payFlowState.equals(PayFlowState.SUCCESS)){
			withdrawState = Constance.WithdrawState.WITHDRAW_STATUS_SUCCESS;
		}else if(payFlowState.equals(PayFlowState.EXCEPTION)){
			withdrawState = Constance.WithdrawState.WITHDRAW_STATUS_EXCEPTION;
		}else if(payFlowState.equals(PayFlowState.FAIL)){
			withdrawState = Constance.WithdrawState.WITHDRAW_STATUS_FAIL;
		}else{
			withdrawState = Constance.WithdrawState.WITHDRAW_STATUS_EXCEPTION;
		}
		
		OrderWithdrawDO orderWithdrawDO = orderWithdrawMysqlDAO.findById(referOrderId);
		WithDrawType withdrawType = WithDrawType.valueOf(orderWithdrawDO.getWithdrawType());
		long withdrawAmount = orderWithdrawDO.getWithdrawAmount();
		long withdrawFee = orderWithdrawDO.getWithdrawFee();
		
		if(orderWithdrawDO.getOrderStatus() == WithdrawState.WITHDRAW_STATUS_SUCCESS.getCode() || 
				orderWithdrawDO.getOrderStatus() == WithdrawState.WITHDRAW_ORDER_FAIL_REFUND.getCode()){
			Log.info("该订单已经完成支付或退款,无需重复回调");
			return;
		}
		if(!payFlowType.equals(PayFlowType.DISTRIBUTE)){
			Log.info("业务类型错误,不允许回调,payFlowType:"+payFlowType);
			return;
		}
		if(payFlowState.equals(PayFlowState.FAIL) && (withdrawType == WithDrawType.WITHDRAW_REBATE || withdrawType == WithDrawType.WITHDRAW_SCAN_REBATE)){
			//需要进行退款
			sendTradeFlowMessage(orderWithdrawDO, 4, "提现失败,退款");
			c2bRefundTansfer(orderWithdrawDO,withdrawType);
		}
		if(resolveTradeInfo(tradeInfo)){
			sendTradeFlowMessage(orderWithdrawDO, 2, "成功");
			callBack(referOrderId, Constance.WithdrawState.WITHDRAW_STATUS_SUCCESS,"SUCCESS");
		}
	}
	/**
	 * 
	 * @param orderTransferDO
	 * @param state  1:支付者扣款成功,2:交易成功,3:交易失败  4：退款
	 */
	private void sendTradeFlowMessage(OrderWithdrawDO orderWithdrawDO,int state,String orderDesc){
		try {
			String platChannelId = orderWithdrawDO.getPlatChannelId();
			if(JFUtils.isJFChannel(platChannelId)){
				return;
			}
			
			TradeFlowMessage successMessage = new TradeFlowMessage();
			if(state == 4){
				successMessage.setTradeType(TradeMessageType.REFUND.getCode());
			}else{
				successMessage.setTradeType(TradeMessageType.WITHDRAW.getCode());
			}
			successMessage.setBerbonAcc(orderWithdrawDO.getPayerUserId());
			successMessage.setBusinessType(orderWithdrawDO.getBusinessType());
			successMessage.setTradeAmount(orderWithdrawDO.getWithdrawAmount());
			successMessage.setReceiveAmount(orderWithdrawDO.getPayAmount());
			successMessage.setOtherBerbonAcc(null);
			successMessage.setPayOrderNo(orderWithdrawDO.getWithdrawOrderId());
			successMessage.setTradeOrderNo(orderWithdrawDO.getOrderId());
			if(state == 1 || state == 2){
				successMessage.setFee(orderWithdrawDO.getWithdrawFee());
			}
			
			if(state != 4){
				successMessage.setInnerState(state);
			}else{
				successMessage.setInnerState(3);
			}
			
			successMessage.setTradeDesc(orderDesc);
			String payType = "";
			if(StringUtil.isNotBlank(orderWithdrawDO.getPayerBindNo())){
				//UserBindCardDO userBindCardDO = accountService.findUserBindInfo(orderWithdrawDO.getPayerBindNo(), orderWithdrawDO.getPayerUserId(), null);
				UserBindCardDO userBindCardDO = accountService.findUserBindInfoIgnoreState(orderWithdrawDO.getPayerBindNo(), orderWithdrawDO.getPayerUserId(), null);
				String cardNo = YHBFSensitiveEnc.sensitiveDec(userBindCardDO.getCardNo(), "cardno");
				cardNo = cardNo.substring(cardNo.length() - 4, cardNo.length());
				payType = userBindCardDO.getBankName() + "(" + cardNo + ")";
			}else{
				payType = "佣金转入余额";
			}
			
			successMessage.setPayType(payType);
			sendTradeFlowMessage(successMessage);
		} catch (Exception e) {
			logger.info("sendTradeFlowMessage  exception 账单mq通知异常",e);
		}
	}
	private boolean sendTradeFlowMessage(TradeFlowMessage message) {
		String json = JSONObject.toJSONString(message);
		mqMessageService.sendTradeFlowMsg(json);
		return true;
	}
	
	//通知业务系统
	@Async
	private void callBack(String withdrawOrderId,WithdrawState state,String orderDesc){
		try {
			Date payTime = new Date();
			OrderWithdrawDO orderWithdrawDO = new OrderWithdrawDO();
			orderWithdrawDO.setWithdrawOrderId(withdrawOrderId);
			orderWithdrawDO.setOrderStatus((byte) state.getCode());
			orderWithdrawDO.setOrderDesc(state.getDesc());
			orderWithdrawDO.setPayTime(payTime);
			orderWithdrawMysqlDAO.update(orderWithdrawDO);
			orderWithdrawDO = orderWithdrawMysqlDAO.findById(withdrawOrderId);
			//通知业务系统
			CallBackOrderState callBackOrderState = null;
			
			String bindNo = orderWithdrawDO.getPayerBindNo();
			UserBindCardDO payerBindCardInfo = null;
			if(StringUtil.isNotBlank(bindNo)){
				payerBindCardInfo = accountService.findUserBindInfoIgnoreState(orderWithdrawDO.getPayerBindNo(), orderWithdrawDO.getPayerUserId(), null);
			}
			
			
			if(state.equals(WithdrawState.WITHDRAW_STATUS_SUCCESS)){
				//成功通知风控系统
//				boolean flag = lockRedisDAO.lockOrder(withdrawOrderId, "success");
//				if (flag) {
//					TranType tradeType = null;
//					WithDrawType withDrawType = WithDrawType.valueOf(orderWithdrawDO.getWithdrawType());
//					int bindType = payerBindCardInfo.getBindType();
//					if(withDrawType.equals(WithDrawType.WITHDRAW_BERBON) && bindType == 2){
//						tradeType = TranType.WITHDRAW_BERBON_BANKCARD;
//					}else if(withDrawType.equals(WithDrawType.WITHDRAW_BERBON) && bindType == 3){
//						tradeType = TranType.WITHDRAW_BERBON_ALIPAY;
//					}else if(withDrawType.equals(WithDrawType.WITHDRAW_REBATE) && bindType == 2){
//						tradeType = TranType.WITHDRAW_PROFIT_BANKCARD;
//					}else if(withDrawType.equals(WithDrawType.WITHDRAW_REBATE) && bindType == 3){
//						tradeType = TranType.WITHDRAW_PROFIT_ALIPAY;
//					}
//				}
				
				callBackOrderState = CallBackOrderState.SUCCESS;
			}else if(state.equals(WithdrawState.WITHDRAW_STATUS_FAIL)){
				callBackOrderState = CallBackOrderState.FAIL;
			}else if(state.equals(WithdrawState.WITHDRAW_STATUS_EXCEPTION)){
				callBackOrderState = CallBackOrderState.EXCEPTION;
			}else{
				throw new BusinessException("非法的业务回调，当前订单状态不允许回调！ withdrawState:"+state);
			}
			
			
			if(state.equals(WithdrawState.WITHDRAW_STATUS_FAIL) || state.equals(WithdrawState.WITHDRAW_STATUS_EXCEPTION) && StringUtil.isNotBlank(bindNo)){
				int withdrawType = orderWithdrawDO.getWithdrawType();
				TradeType tradeType = null;
				int bindType = payerBindCardInfo.getBindType();
				if(withdrawType == 1 && bindType == 2){
					tradeType = TradeType.WITHDRAW_BERBON_BANKCARD;
				}else if(withdrawType == 1 && bindType == 3){
					tradeType = TradeType.WITHDRAW_BERBON_ALIPAY;
				}else if((withdrawType == 2 || withdrawType == 3) && bindType == 2){
					tradeType = TradeType.WITHDRAW_PROFIT_BANKCARD;
				}else if((withdrawType == 2 || withdrawType == 3) && bindType == 3){
					tradeType = TradeType.WITHDRAW_PROFIT_ALIPAY;
				}
				this.newupdateRisk(tradeType, orderWithdrawDO.getOrderId(), orderWithdrawDO.getPlatChannelId(), 
						orderWithdrawDO.getBusinessType(), null, orderWithdrawDO.getPayerUserId(), 
						null, -orderWithdrawDO.getPayAmount().intValue(), String.valueOf(orderWithdrawDO.getWithdrawChannel()), 
						orderWithdrawDO.getSourceIp(), null, false,orderWithdrawDO.getAddTime());
			}
			
			WithDrawType withDrawType = WithDrawType.valueOf(orderWithdrawDO.getWithdrawType());
			TradeOrderType tradeOrderType = null;
			if(withDrawType.equals(WithDrawType.WITHDRAW_BERBON)){
				tradeOrderType = TradeOrderType.BALANCE_WITHDRAW_ORDER;
			}else if(withDrawType.equals(WithDrawType.WITHDRAW_REBATE) || withDrawType.equals(WithDrawType.WITHDRAW_SCAN_REBATE)){
				tradeOrderType = TradeOrderType.PROFIT_WITHDRAW_ORDER;
			}
			CallBackInfo callBackInfo = new CallBackInfo();
			callBackInfo.setTradeOrderId(withdrawOrderId);
			callBackInfo.setOutOrderId(orderWithdrawDO.getOrderId());
			callBackInfo.setNotfiyUrl(orderWithdrawDO.getNotifyUrl());
			callBackInfo.setReturnUrl(orderWithdrawDO.getReturnUrl());
			callBackInfo.setTotalFee(orderWithdrawDO.getWithdrawFee().intValue());
			callBackInfo.setPayAmount(orderWithdrawDO.getWithdrawAmount().intValue());
			callBackInfo.setAttach(orderWithdrawDO.getRemark());
			callBackInfo.setPayTime(payTime);
			callBackInfo.setTradeCrateTime(orderWithdrawDO.getAddTime());
			callBackInfo.setOrderType(tradeOrderType);
			callBackInfo.setOrderState(callBackOrderState);
			callBackInfo.setOrderDesc(orderDesc);
			callBackService.callBack(callBackInfo );
		} catch (Exception e) {
			logger.info("callback exception  业务回调通知异常",e);
		}
		
	}
	
	//判断是否可以立即提现
	private boolean withDrawNow(OrderWithdrawDO orderWithdrawDO){
		//此时需要判断withdrawTime  为空或者达到提现条件 需要立即代发    否则是job定时去代发
		boolean withdrawNow = false;
		String withdrawTime = orderWithdrawDO.getWithdrawTime();
		if(StringUtil.isNotBlank(withdrawTime)){
			Date withdrawDate = DateUtil.parse(withdrawTime, "yyyyMMddHHmmss");
			Date nowDate = new Date();
			if(!withdrawDate.after(nowDate)){
				withdrawNow = true;
			}
		}else{
			withdrawNow = true;
		}
		return withdrawNow;
	}
	
	//代发
	public PayCoreResult innerWithDraw(OrderWithdrawDO orderWithdrawDO){
		WithDrawType withdrawType = WithDrawType.valueOf(orderWithdrawDO.getWithdrawType());
		TradeOrderType tradeOrderType = withdrawType == 
				WithDrawType.WITHDRAW_BERBON ? TradeOrderType.BALANCE_WITHDRAW_ORDER : TradeOrderType.PROFIT_WITHDRAW_ORDER;
		String mappingOrderId = orderMappingService.addMappingOrder(orderWithdrawDO.getWithdrawOrderId(), (byte)tradeOrderType.getCode());
		
		PayCoreDistribute payCoreDistribute = new PayCoreDistribute();
//		if(withdrawType.equals(WithDrawType.WITHDRAW_REBATE)){
//			payCoreDistribute.setPayerActNo(Constance.ACT_PROFIT);
//			payCoreDistribute.setPayerUserType(1);
//			payCoreDistribute.setPayerActType(UserActType.CASH);
//			payCoreDistribute.setPayerUserId(Constance.USER_ID_SZTX);
//		}else if(withdrawType.equals(WithDrawType.WITHDRAW_BERBON)){
//			payCoreDistribute.setPayerActNo(payerActInfo.getActNo());
//			payCoreDistribute.setPayerUserType(payerActInfo.getUserType());
//			payCoreDistribute.setPayerActType(UserActType.valueOf(payerActInfo.getActType()));
//			payCoreDistribute.setPayerUserId(payerActInfo.getUserId());
//		}
		payCoreDistribute.setPayerActNo(payerActInfo.getActNo());
		payCoreDistribute.setPayerUserType(payerActInfo.getUserType());
		payCoreDistribute.setPayerActType(UserActType.valueOf(payerActInfo.getActType()));
		payCoreDistribute.setPayerUserId(payerActInfo.getUserId());
		
		
		Integer	cardActType = payerBindCardInfo.getCardActType();
		String	realName = payerBindCardInfo.getRealName();
		String cardProvince = payerBindCardInfo.getCardProvince();
		String cardCity = payerBindCardInfo.getCardCity();
		CardActType paycardActType = null;
		if(cardActType != null){
			paycardActType = CardActType.valueOf(cardActType);
		}
		DistributeType distributeType = null;
		if(payerBindCardInfo.getBindType() == 2){
			distributeType = DistributeType.BANK;
		}else if(payerBindCardInfo.getBindType() == 3){
			distributeType = DistributeType.ALIPAY;
		}
		
		
		payCoreDistribute.setReferOrderId(mappingOrderId);
		payCoreDistribute.setTradeOrderType(tradeOrderType);
		payCoreDistribute.setPayeeUserId(orderWithdrawDO.getPayerUserId());
		payCoreDistribute.setPayeeUserType(payerActInfo.getUserType());
		payCoreDistribute.setPayeeAccountId(payerBindCardInfo.getCardNo());
		payCoreDistribute.setPayeeActType(UserActType.valueOf(payerActInfo.getActType()));

		payCoreDistribute.setAmount(orderWithdrawDO.getWithdrawAmount());
		
		payCoreDistribute.setDistributeType(distributeType);
		payCoreDistribute.setFeeAmount(orderWithdrawDO.getWithdrawFee());
		payCoreDistribute.setOriginOrderNo(orderWithdrawDO.getWithdrawOrderId());
		
		
		
		payCoreDistribute.setAttach(orderWithdrawDO.getRemark());
		payCoreDistribute.setRealName(realName);
		payCoreDistribute.setCardActType(paycardActType );
		payCoreDistribute.setCardProvince(cardProvince);
		payCoreDistribute.setCardCity(cardCity);
		
		payCoreDistribute.setBusinessType(orderWithdrawDO.getBusinessType());
		
		
		if(cardActType != null && cardActType == CardActType.CARD_ACT_PUBLIC.getValue()){
			String bankId = payerBindCardInfo.getBankId();
			if(StringUtil.isBlank(bankId)){
				String swiftCode = payerBindCardInfo.getSwiftCode();
				if(StringUtil.isNotBlank(swiftCode)){
					bankId = gatewaySwiftCodeBankIdMappingMysqlDAO.getBankIdBySwiftCode(swiftCode, 6);
				}
			}
			payCoreDistribute.setBankId(bankId);
		}
		
		
		
		
		PayCoreResult result = payCoreService.distribute(payCoreDistribute , "tradeWithdrawService");
		
		OrderWithdrawDO uporderWithdrawDO = new OrderWithdrawDO();
		uporderWithdrawDO.setWithdrawOrderId(orderWithdrawDO.getWithdrawOrderId());
		uporderWithdrawDO.setPayChannelId(result.getChannelId());
		
		uporderWithdrawDO.setOrderStatus((byte)WithdrawState.WITHDRAW_ORDER_SUBMIT.getCode());
		uporderWithdrawDO.setOrderDesc(WithdrawState.WITHDRAW_ORDER_SUBMIT.getDesc());
		orderWithdrawMysqlDAO.update(uporderWithdrawDO);	
		
		
		return result;
	}
	
	
	/**
	 * 
	 * @param orderWithdrawDO
	 */
	private void b2cTansfer(OrderWithdrawDO orderWithdrawDO,WithDrawType withDrawType){
		String mappingOrderId = orderMappingService.addMappingOrder(orderWithdrawDO.getWithdrawOrderId(), (byte)TradeOrderType.TRANSFER_ORDER.getCode());
		PayCoreTransferReq req = new PayCoreTransferReq();
		req.setAmount(orderWithdrawDO.getWithdrawAmount());
		req.setFeeAmount(0);
		req.setAttach("返利金转入用户余额");
		req.setOrderId(mappingOrderId);
		req.setOriginOrderId(orderWithdrawDO.getWithdrawOrderId());
		
		if(withDrawType==WithDrawType.WITHDRAW_REBATE){
			req.setPayerActNo(Constance.ACT_REBATE);
			req.setPayerUserId(Constance.USER_REBATE);
		}else if(withDrawType==WithDrawType.WITHDRAW_SCAN_REBATE){
			req.setPayerActNo(Constance.ACT_SCAN_REBATE);
			req.setPayerUserId(Constance.USER_SCAN_REBATE);
		}
		
		req.setPayerUserType(1);
		req.setPayerActType(UserActType.CASH);
		
		
		req.setPayeeActNo(payerActInfo.getActNo());
		req.setPayeeUserType(payerActInfo.getUserType());
		req.setPayeeActType(UserActType.valueOf(payerActInfo.getActType()));
		req.setPayeeUserId(payerActInfo.getUserId());
		
		req.setTradeOrderType(TradeOrderType.TRANSFER_ORDER);
		req.setBusinessType(orderWithdrawDO.getBusinessType());
		try {
			payCoreService.balanceTransfer(req );
			updateWithDrawOrderState(orderWithdrawDO.getWithdrawOrderId(), WithdrawState.WITHDRAW_DEBIT_SUCCESS);
		} catch (Exception e) {
			updateWithDrawOrderState(orderWithdrawDO.getWithdrawOrderId(), WithdrawState.WITHDRAW_STATUS_FAIL);
			throw new BusinessException(e.getMessage());
		}
	}
	
	/**
	 * 
	 * @param orderWithdrawDO
	 */
	private void c2bRefundTansfer(OrderWithdrawDO orderWithdrawDO,WithDrawType withDrawType){
		String mappingOrderId = orderMappingService.addMappingOrder(orderWithdrawDO.getWithdrawOrderId(), (byte)TradeOrderType.TRANSFER_ORDER.getCode());
		PayCoreTransferReq req = new PayCoreTransferReq();
		req.setAmount(orderWithdrawDO.getWithdrawAmount());
		req.setFeeAmount(0);
		req.setAttach("提现失败,用户余额退回返利金账户");
		req.setOrderId(mappingOrderId);
		req.setOriginOrderId(orderWithdrawDO.getWithdrawOrderId());
		
		if(withDrawType==WithDrawType.WITHDRAW_REBATE){
			req.setPayeeActNo(Constance.ACT_REBATE);
			req.setPayeeUserId(Constance.USER_REBATE);
		}else if(withDrawType==WithDrawType.WITHDRAW_SCAN_REBATE){
			req.setPayeeActNo(Constance.ACT_SCAN_REBATE);
			req.setPayeeUserId(Constance.USER_SCAN_REBATE);
		}
		
		req.setPayeeUserType(1);
		req.setPayeeActType(UserActType.CASH);
		
		
		
		UserActDO payerActInfo = getPayerActInfo(orderWithdrawDO.getPayerUserId(), orderWithdrawDO.getPlatChannelId());
		req.setPayerActNo(payerActInfo.getActNo());
		req.setPayerUserType(payerActInfo.getUserType());
		req.setPayerActType(UserActType.valueOf(payerActInfo.getActType()));
		req.setPayerUserId(payerActInfo.getUserId());
		
		req.setTradeOrderType(TradeOrderType.TRANSFER_ORDER);
		req.setBusinessType(orderWithdrawDO.getBusinessType());
		try {
			payCoreService.balanceTransfer(req );
			updateWithDrawOrderState(orderWithdrawDO.getWithdrawOrderId(), WithdrawState.WITHDRAW_ORDER_FAIL_REFUND);
		} catch (Exception e) {
			updateWithDrawOrderState(orderWithdrawDO.getWithdrawOrderId(), WithdrawState.WITHDRAW_ORDER_REFUND_FAIL);
			throw new BusinessException(e.getMessage());
		}
	}
	
	private boolean resolveTradeInfo(PayCoreTradeInfo tradeInfo){
		PayFlowState payFlowState = tradeInfo.getPayFlowState();
		String mappingOrderId = tradeInfo.getReferOrderId();
		
		
		//映射表反查订单
		String referOrderId = orderMappingService.getTradeOrderId(mappingOrderId);
	
		if(payFlowState != PayFlowState .SUCCESS){
			if(payFlowState == PayFlowState.FAIL){
				updateWithDrawOrderState(referOrderId, WithdrawState.WITHDRAW_STATUS_FAIL);
				callBack(referOrderId, Constance.WithdrawState.WITHDRAW_STATUS_FAIL,tradeInfo.getPayFlowDesc());
			}else if(payFlowState == PayFlowState.EXCEPTION){
				updateWithDrawOrderState(referOrderId, WithdrawState.WITHDRAW_STATUS_EXCEPTION);
				callBack(referOrderId, Constance.WithdrawState.WITHDRAW_STATUS_EXCEPTION,tradeInfo.getPayFlowDesc());
			}else{
				updateWithDrawOrderState(referOrderId, WithdrawState.WITHDRAW_STATUS_EXCEPTION);
				callBack(referOrderId, Constance.WithdrawState.WITHDRAW_STATUS_EXCEPTION,tradeInfo.getPayFlowDesc());
			}
			return false;
		}else{
			return true;
		}
	}
	
	public TradeResponse refund(String tradeOrderId){
		TradeResponse response = new TradeResponse();
		OrderWithdrawDO orderWithdrawDO = orderWithdrawMysqlDAO.findById(tradeOrderId);
		Byte orderStatus = orderWithdrawDO.getOrderStatus();
		WithdrawState withDrawState = WithdrawState.valueOf(orderStatus);
		WithDrawType withdrawType = WithDrawType.valueOf(orderWithdrawDO.getWithdrawType());
		if(withDrawState == WithdrawState.WITHDRAW_STATUS_FAIL && (withdrawType == WithDrawType.WITHDRAW_REBATE || withdrawType == WithDrawType.WITHDRAW_SCAN_REBATE)){
			c2bRefundTansfer(orderWithdrawDO,withdrawType);
			response.setResultCode(String.valueOf(PayFlowState.SUCCESS.getCode()));
			response.setResultMsg(PayFlowState.SUCCESS.getDesc());
		}else{
			throw new BusinessException("该订单不允许进行退款!");
		}
		return response;
	}
//	public TradeResponse reSubOrder(String tradeOrderId){
//		TradeResponse response = new TradeResponse();
//		OrderWithdrawDO orderWithdrawDO = orderWithdrawMysqlDAO.findById(tradeOrderId);
//		Byte orderStatus = orderWithdrawDO.getOrderStatus();
//		WithdrawState withDrawState = WithdrawState.valueOf(orderStatus);
//		WithDrawType withdrawType = WithDrawType.valueOf(orderWithdrawDO.getWithdrawType());
//		if(withDrawState == WithdrawState.WITHDRAW_STATUS_FAIL )
//	}
}
